using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEngine;

public class EmojiEditor 
{
    [MenuItem("Assets/创建Emoji图集")]
    public static void Create()
    {
        var guids = Selection.assetGUIDs;
        if (guids != null)
        {
            for (int i = 0; i < guids.Length; i++)
            {
                string path = AssetDatabase.GUIDToAssetPath(guids[i]);
                if (Directory.Exists(path))
                {
                    string[] files = Directory.GetFiles(path,"*.png");
                    int c = files.Length;
                    int count = (int)Mathf.Sqrt(c) + 1;
                    //int pix = (int)(2048f / count - 1f);
                    PackTexture2(files, count);
                }
            }
        }
    }
    static void PackTexture(string[] files, int pix)
    {
        Texture2D[] textures = new Texture2D[files.Length];
        RenderTexture rt = new RenderTexture(pix,pix,0,RenderTextureFormat.ARGB32);
        RenderTexture prev = RenderTexture.active;
        RenderTexture.active = rt;
        Texture2D t2d = new Texture2D(2048, 2048, TextureFormat.ARGB32, false);
        int sx = 0;
        int sy = 0;
        for (int i=0;i<textures.Length;i++)
        {
            if (sx + pix > 2048)
            {
                sx = 0;
                sy += pix;
            }
            var tt = AssetDatabase.LoadAssetAtPath<Texture2D>(files[i]);
            Graphics.Blit(tt, rt);
            //Graphics.CopyTexture(rt, 0, 0, 0, 0, pix, pix, t2d, 0, 0, sx, sy);
            t2d.ReadPixels(new Rect(0, 0, pix, pix), sx, sy);
            sx += pix;
        }
        
        RenderTexture.active = prev;
        // Rect[] rects =  t2d.PackTextures(textures,0);
        t2d.Apply();
        byte[] dats = t2d.EncodeToPNG();
        File.WriteAllBytes("Assets/emojis.png",dats);
        UnityEngine.Object.DestroyImmediate(t2d);
        UnityEngine.Object.DestroyImmediate(rt);
        AssetDatabase.Refresh();
        Debug.Log("合成完毕");
    }
    static void PackTexture2(string[] files, int count)
    {
        Texture2D[] textures = new Texture2D[files.Length];
        int size = 74 * count;
        Texture2D t2d = new Texture2D(size, size, TextureFormat.ARGB32, false);
        Color32[] fill = new Color32[size*size];
        t2d.SetPixels32(fill);
        int sx = 0;
        int sy = 0;
        Vector4 uv;
        float w = size;
        //List<uint> buffer = new List<uint>();
        //EmojiInfo[] emojis = new EmojiInfo[textures.Length];
        Vector4[] emojis = new Vector4[textures.Length];
        for (int i = 0; i < textures.Length; i++)
        {
            if (sx + 74 > size)
            {
                sx = 0;
                sy += 74;
            }
            var tt = AssetDatabase.LoadAssetAtPath<Texture2D>(files[i]);
            Graphics.CopyTexture(tt, 0, 0, 0, 0, 72, 72, t2d, 0, 0, sx, sy);
    
            float ux = sx;
            float uy = sy;
            uv.x = ux / w;
            uv.y = uy / w;
            uv.z = (ux + 72.0f) / w;
            uv.w = (uy + 72.0f) / w;
            //buffer.Add(bit);
            //emojis[i].Code = bit;
            emojis[i] = uv;
            sx += 74;
        }
        // Rect[] rects =  t2d.PackTextures(textures,0);
        t2d.Apply();
        byte[] dats = t2d.EncodeToPNG();
        File.WriteAllBytes("Assets/emojis.png", dats);
        UnityEngine.Object.DestroyImmediate(t2d);

        EmojiMap.Build(files,emojis);
        //unsafe
        //{
        //    byte[] dat = new byte[emojis.Length * sizeof(EmojiInfo)];
        //    fixed(EmojiInfo* ep=&emojis[0])
        //    {
        //        byte* bp = (byte*)ep;
        //        for (int i = 0; i < dat.Length; i++)
        //        {
        //            dat[i] = bp[i];
        //        }
        //    }
        //    File.WriteAllBytes("Assets/emojis.bytes", dat);
        //}
        AssetDatabase.Refresh();
        Debug.Log("合成完毕");
    }

    static void CreateUVInfo(string[] files, int pix)
    {
        List<uint> buffer = new List<uint>();
        for (int i = 0; i <files.Length; i++)
        {
            string name = new FileInfo(files[i]).Name.Split('.')[0];
            string[] codes = name.Split(' ');
            string str = "";
            for (int j = 0; j < codes.Length; j++)
            {
                UInt32 value = Codepoint(codes[j]);
                str += AsString(value);
            }
            var bit = UnicodeEx.GetUnicode(str, 0);
            if(buffer.Contains(bit))
            {
                Debug.LogError("编码重复:"+ name);
                Debug.Log(bit);
                break;
            }
            else
            {
                buffer.Add(bit);
            }
        }
        Debug.Log("done");
    }
    static UInt32 Codepoint(string hexValue)
    {
        if ((hexValue.StartsWith("0x") || hexValue.StartsWith("U+") || hexValue.StartsWith("u+")))
        {
            hexValue = hexValue.Substring(2);
        }
        if (!UInt32.TryParse(hexValue, NumberStyles.HexNumber, CultureInfo.CurrentCulture.NumberFormat, out UInt32 Value))
        {
            Debug.LogError("错误编码:"+hexValue);
        }
        return Value;
    }
    static void AsUtf32Bytes(Span<byte> dest, UInt32 Value)
    {
        if (dest.Length < 4)
        {
            throw new ArgumentException("dest must be a 4-byte array");
        }

        var utf32 = Value;
        dest[0] = (byte)(utf32 >> 24);
        dest[1] = (byte)((utf32 & 0x00FFFFFF) >> 16);
        dest[2] = (byte)(((UInt16)utf32) >> 8);
        dest[3] = (byte)utf32;
    }
    static int AsUtf16Bytes(Span<byte> dest,UInt32 Value)
    {
        // U+0000 to U+D7FF and U+E000 to U+FFFF
        if (Value <= 0xFFFF)
        {
            dest[0] = (byte)(Value);
            dest[1] = (byte)(Value >> 8);
            return 2;
        }

        // U+10000 to U+10FFFF
        if (Value >= 0x10000 && Value <= 0x10FFFF)
        {
            UInt32 newVal = Value - 0x010000; // leaving 20 bits
            UInt16 high = (UInt16)((newVal >> 10) + 0xD800);
            System.Diagnostics.Debug.Assert(high <= 0xDBFF && high >= 0xD800);
            dest[0] = (byte)(high);
            dest[1] = (byte)(high >> 8);

            UInt16 low = (UInt16)((newVal & 0x03FF) + 0xDC00);
            System.Diagnostics.Debug.Assert(low <= 0xDFFF && low >= 0xDC00);
            dest[2] = (byte)(low);
            dest[3] = (byte)(low >> 8);
            return 4;
        }
        Debug.LogError("错误编码:" + Value.ToString());
        return 0;
      
    }
    static string AsString(UInt32 Value)
    {
        Span<byte> bytes = stackalloc byte[4];
        var count = AsUtf16Bytes(bytes,Value);
        unsafe
        {
            fixed (byte* ptr = bytes)
            {
                return Encoding.Unicode.GetString(ptr, count);
            }
        }
    }

    struct EmojiInfo
    {
        public uint Code;
        public Vector4 uv;
    }
}
